#if !defined(ximera_threading_thread_hpp)
#define ximera_threading_thread_hpp

// -----------------------------------------------------------

#include <boost/thread/thread.hpp>
#include <boost/function.hpp>
#include <ximera/exception.hpp>

namespace ximera { namespace threading
{
    //! \brief Exception for thread errors
    XIMERA_DECLARE_EXCEPTION(ThreadException, L"Thread error");

    /*! \ brief The Thread class represents threads of execution.
     *
     *  A thread of execution has an initial function. The initial function is RunFunc(isTerminated()) 
     *  of the function object assigned to the runFunc property.
     *
     *  A thread of execution is said to be "finished" or to have "finished execution" when its runFunc()
     *  function returns or is terminated.
     */
    class XIMERA_API Thread
    {
    public:
        //! \brief Declaration of the type of function that will be passed to runFunc to verify if the thread is finished
        typedef boost::function<bool ()> ShouldExitFunction;

        //! \brief Declaration of the type of function that will be executed in a thread of execution
        typedef boost::function<void (ShouldExitFunction const&)> RunFunction;

        //! \brief Create an instance of Thread 
        Thread();

        /*! \brief Create an instance of Thread 
         *  \param function The RunFunc that will be initialized from the begginig
         */
        Thread(RunFunction const& function);

        ~Thread();

        /*! \brief Starts the thread of execution.
         *
         * This functions creates a new thread of execution and calls the runFunc() 
         * function on that thread of execution.
         */
        void start();

        //! \brief Signals the thread that it has to stop 
        void stop();

        //! \brief The current thread of execution blocks until the initial function of the thread of execution finishes 
        void join();

        //! \brief Utility function that calls stop() first and then calls join()
        void stopAndJoin();

        //! \brief Returns true if the thread is actualy running or false otherwise
        bool isRunning();

        /*! \brief Function called inside the thread of execution.
         *  \param function The function that will be called inside the thread.
         * 
         * This function is called inside the thread, passing IsTerminatedFunc parameter that will be used
         * on the function to know when the thread needs to stop.
         */
        void runFunction(RunFunction const& function);

        /*! \brief The current thread of execution blocks until millisecs is reached
         *  \param millisecs The amount of milli seconds that the thread of execution blocks.
         */
        static void sleep(UInt32 millisecs);

    private:

        RunFunction _runFunction;
        boost::thread* _thread;
        bool _running;
        bool _shouldExit;

        void internalRun();
        bool shouldExit();
    };
}}

// -----------------------------------------------------------

#endif